/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.netbeans.modules.debugger.jpda;
import java.beans.*;
import java.util.*;
import com.sun.jdi.ThreadReference;
import com.sun.jdi.StackFrame;
import com.sun.jdi.Method;
import com.sun.jdi.LocalVariable;
import com.sun.jdi.IncompatibleThreadStateException;
import com.sun.jdi.InvalidTypeException;
import com.sun.jdi.VMDisconnectedException;
import com.sun.jdi.ObjectCollectedException;
import com.sun.jdi.InvalidStackFrameException;
import com.sun.jdi.AbsentInformationException;
import javax.swing.SwingUtilities;
import org.openide.debugger.DebuggerException;
import org.openide.text.Line;
import org.openide.util.RequestProcessor.Task;
import org.netbeans.modules.debugger.support.AbstractThread;
import org.netbeans.modules.debugger.support.AbstractDebugger;
import org.netbeans.modules.debugger.support.AbstractVariable;
import org.netbeans.modules.debugger.support.CallStackFrame;
import org.netbeans.modules.debugger.support.util.Utils;
import org.netbeans.modules.debugger.support.util.Protector;
/**
* JPDA Implementation of debugger thread.
*/
public class JPDAThread extends AbstractThread {
// variables .......................................................................
private JPDADebugger debugger;
private ThreadReference thread;
private boolean current = false;
/** Cache for old locales value. */
private HashMap oldLocales = new HashMap ();
/** Cache for old call stack. */
private JPDACallStackFrame [] oldCallStack = new JPDACallStackFrame [0];
// init ............................................................................
JPDAThread (
JPDADebugger debugger,
JPDAThreadGroup parentThreadGroup,
ThreadReference thread
) {
super (debugger, parentThreadGroup);
this.thread = thread;
this.debugger = debugger;
}
// implementation of DebuggerThread ................................................
/**
* Getter for the name of thread property.
*
* @throw DebuggerException if some problem occurs.
* @return name of thread.
*/
public String getName () throws DebuggerException {
Task t = Protector.register ("JPDAThread.getName"); // NOI18N
try {
return thread.name ();
} catch (Exception e) {
return "Thread"; // NOI18N
} finally {
t.cancel ();
}
}
/**
* If this thread is suspended returns line number where this thread is stopped.
*
* @throw DebuggerException if some problem occurs.
* @return line number where this thread is stopped.
*/
public int getLineNumber () throws DebuggerException {
Task t = Protector.register ("JPDAThread.getLineNumber"); // NOI18N
try {
if (thread.frameCount () < 1)
return -1;
return thread.frame (0).location ().lineNumber ();
} catch (Exception e) {
return -1;
} finally {
t.cancel ();
}
}
/**
* Returns string representation of the current state of this thread (depends on
* debugger implementation).
*
* @throw DebuggerException if some problem occurs.
* @return string representation of the current state of this thread.
*/
public String getState () throws DebuggerException {
Task t = Protector.register ("JPDAThread.getState"); // NOI18N
try {
int s = thread.status ();
switch (s) {
case ThreadReference.THREAD_STATUS_UNKNOWN: // [PENDING] - localization!!!
return "Unknown"; // NOI18N
case ThreadReference.THREAD_STATUS_ZOMBIE:
return "Zombie"; // NOI18N
case ThreadReference.THREAD_STATUS_RUNNING:
return "Running"; // NOI18N
case ThreadReference.THREAD_STATUS_SLEEPING:
return "Sleeping"; // NOI18N
case ThreadReference.THREAD_STATUS_MONITOR:
return "Monitor"; // NOI18N
case ThreadReference.THREAD_STATUS_WAIT:
return "Wait"; // NOI18N
case ThreadReference.THREAD_STATUS_NOT_STARTED:
return "Not started"; // NOI18N
}
return "Unknown"; // NOI18N
} catch (Exception e) {
return "Undefined"; // NOI18N
} finally {
t.cancel ();
}
}
/**
* If this thread is suspended returns class name where this thread is stopped.
*
* @throw DebuggerException if some problem occurs.
* @return class name where this thread is stopped.
*/
public String getClassName () throws DebuggerException {
Task t = Protector.register ("JPDAThread.getClassName"); // NOI18N
try {
if (thread.frameCount () < 1)
return ""; // NOI18N
return thread.frame (0).location ().declaringType ().name ();
} catch (Exception e) {
return ""; // NOI18N
} finally {
t.cancel ();
}
}
/**
* If this thread is suspended returns method name where this thread is stopped.
*
* @throw DebuggerException if some problem occurs.
* @return method name where this thread is stopped.
*/
public String getMethod () throws DebuggerException {
Task t = Protector.register ("JPDAThread.getMethod"); // NOI18N
try {
if (thread.frameCount () < 1)
return ""; // NOI18N
Method m = thread.frame (0).location ().method ();
if (m == null)
return ""; // NOI18N
return m.name ();
} catch (Exception e) {
return ""; // NOI18N
} finally {
t.cancel ();
}
}
/**
* Returns current stack depth.
*
* @throw DebuggerException if some problem occurs.
* @return current stack depth.
*/
public int getStackDepth () throws DebuggerException {
Task t = Protector.register ("JPDAThread.getStackDepth"); // NOI18N
try {
return thread.frameCount ();
} catch (Exception e) {
return 0;
} finally {
t.cancel ();
}
}
/**
* Returns true if this thread is suspended.
*
* @throw DebuggerException if some problem occurs.
* @return true if this thread is suspended.
*/
public boolean isSuspended () throws DebuggerException {
Task t = Protector.register ("JPDAThread.isSuspended"); // NOI18N
try {
return thread.isSuspended ();
} catch (Exception e) {
return false;
} finally {
t.cancel ();
}
}
/**
* Setter method for the suspend property.
*
* @throw DebuggerException if some problem occurs.
* @param suspend true if this thread might be suspend.
*/
public void setSuspended (final boolean suspend) throws DebuggerException {
Task t = Protector.register ("JPDAThread.setSuspended"); // NOI18N
try {
if (thread.status () != ThreadReference.THREAD_STATUS_ZOMBIE) {
if (suspend) {
if (!isSuspended ()) {
thread.suspend ();
// firePropertyChange (null, null, null);
}
} else
if (isSuspended ()) {
debugger.removeStepRequest ();
thread.resume ();
// firePropertyChange (null, null, null);
}
super.setSuspended (suspend);
}
} catch (Exception e) {
} finally {
t.cancel ();
}
}
/**
* Stops this thread.
*
* @throw DebuggerException if some problem occurs.
*/
public void stop () throws DebuggerException {
Task t = Protector.register ("JPDAThread.stop"); // NOI18N
try {
thread.stop (null);
firePropertyChange (null, null, null);
} catch (Exception e) {
} finally {
t.cancel ();
}
}
/**
* If this thread is suspended returns current call stack.
*
* @return current call stack.
*/
public CallStackFrame[] getCallStack () {
Task t = Protector.register ("JPDAThread.getCallStack"); // NOI18N
try {
List l = thread.frames ();
JPDACallStackFrame[] sfs = new JPDACallStackFrame [l.size ()];
int i, k = Math.min (sfs.length, oldCallStack.length);
for (i = 0; i < k; i++) {
sfs [sfs.length-i-1] = new JPDACallStackFrame (debugger, (StackFrame) l.get (sfs.length-i-1));
sfs [sfs.length-i-1].oldLocales = oldCallStack [oldCallStack.length-i-1].oldLocales;
}
for (i = k; i < sfs.length; i++)
sfs [sfs.length-i-1] = new JPDACallStackFrame (debugger, (StackFrame) l.get (sfs.length-i-1));
oldCallStack = sfs;
return sfs;
} catch (Exception e) {
oldCallStack = new JPDACallStackFrame [0];
return oldCallStack;
} finally {
t.cancel ();
}
}
/**
* If this thread is suspended returns current local variables.
*
* @return current local variables.
*/
public AbstractVariable[] getLocales () {
Task t = Protector.register ("JPDAThread.getLocales"); // NOI18N
try {
if (thread.frameCount () < 1)
return new AbstractVariable [0];
StackFrame stackFrame = thread.frame (0);
HashMap newLocales = new HashMap ();
List l = stackFrame.visibleVariables ();
int i, k = l.size ();
JPDAVariable[] variables = new JPDAVariable [k];
for (i = 0; i < k; i++) {
LocalVariable lv = (LocalVariable) l.get (i);
variables [i] = (JPDAVariable) oldLocales.get (lv.name ());
if (variables [i] == null)
variables [i] = new JPDAVariable (
debugger,
lv.name (),
stackFrame.getValue (lv),
lv.typeName (),
stackFrame
);
else {
variables [i].update (
lv.name (),
stackFrame.getValue (lv),
lv.typeName (),
stackFrame
);
variables [i].firePropertyChange ();
}
newLocales.put (lv.name (), variables [i]);
}
oldLocales = newLocales;
return variables;
} catch (Exception e) {
return new AbstractVariable [0];
} finally {
t.cancel ();
}
}
/**
* Returns name of file of this frame or null if thread has no frame.
*
* @return Returns name of file of this frame.
* @throws DebuggerException if informations about source are not included or some other error
* occurres.
*/
public String getSourceName () throws DebuggerException {
Task t = Protector.register ("JPDAThread.getSourceName"); // NOI18N
try {
if (thread.frameCount () < 1) return null;
return thread.frame (0).location ().sourceName ();
} catch (Exception e) {
throw new DebuggerException (e);
} finally {
t.cancel ();
}
}
public ThreadReference getThreadReference () {
return thread;
}
/**
* Refresh of thread properties - fires changes.
*/
void refresh () {
firePropertyChange (null, null, null);
}
public String toString () {
try {
return "Thread: " + getName () + " (" + super.toString () + ")"; // NOI18N
} catch (Exception e) {
return super.toString ();
}
}
}
/*
* Log
* 12 Gandalf-post-FCS1.10.3.0 3/28/00 Daniel Prusa
* 11 Gandalf 1.10 1/13/00 Daniel Prusa NOI18N
* 10 Gandalf 1.9 12/10/99 Jan Jancura Deadlock protection for
* JPDA
* 9 Gandalf 1.8 11/29/99 Jan Jancura
* 8 Gandalf 1.7 11/8/99 Jan Jancura Somma classes renamed
* 7 Gandalf 1.6 10/23/99 Ian Formanek NO SEMANTIC CHANGE - Sun
* Microsystems Copyright in File Comment
* 6 Gandalf 1.5 9/28/99 Jan Jancura
* 5 Gandalf 1.4 9/15/99 Jan Jancura
* 4 Gandalf 1.3 9/9/99 Jan Jancura catching exceptions &
* locales repaired
* 3 Gandalf 1.2 9/2/99 Jan Jancura
* 2 Gandalf 1.1 8/17/99 Jan Jancura Actions for session
* added & Thread group current property
* 1 Gandalf 1.0 7/13/99 Jan Jancura
* $
*/